Custom Display Logic Exercises


In [ ]:
from IPython.display import display
from IPython.display import (
    display_png, display_html, display_latex,
    display_javascript, display_svg
)

Circle class with custom display methods

Write a simple MyCircle Python class. Here is a skeleton to get you started:

class MyCircle(object):
    def __init__(self, center=(0.0,0.0), radius=1.0, color='blue'):
        self.center = center
        self.radius = radius
        self.color = color

Now add special display methods to this class for the following representations (remember to wrap them in Python strings):

For HTML:

For SVG:

<svg width="100px" height="100px">
    <circle cx="50" cy="50" r="20" stroke="black" stroke-width="1" fill="white"/>
</svg>

For LaTeX (wrap with $ and use a raw Python string):

\bigcirc

For JavaScript:

alert('I am a circle!');

After you write the class, create an instance and then use display_html, display_svg, display_latex and display_javascript to display those representations.

Solution

Here is the solution to the simple MyCircle class:


In [ ]:
%load soln/mycircle.py

Now create an instance and use the display methods:


In [ ]:
c = MyCircle()

In [ ]:
display(c)

In [ ]:
display_html(c)

In [ ]:
display_svg(c)

In [ ]:
display_latex(c)

In [ ]:
display_javascript(c)

PNG formatter for MyCircle


In [ ]:
%matplotlib inline
from matplotlib import pyplot as plt

Now let's assume that the MyCircle class has already been defined and add a PNG representation using a formatter display function. Here is a function that converts a MyCircle instance to raw PNG data.


In [ ]:
from IPython.core.pylabtools import print_figure

def circle_to_png(circle):
    """Render AnotherCircle to png data using matplotlib"""
    fig, ax = plt.subplots()
    patch = plt.Circle(circle.center,
                       radius=circle.radius,
                       fc=circle.color,
                       )
    ax.add_patch(patch)
    plt.axis('scaled')
    data = print_figure(fig, 'png')
    # We MUST close the figure, otherwise IPython's display machinery
    # will pick it up and send it as output, resulting in a double display
    plt.close(fig)
    return data

Now use the IPython API to get the PNG formatter (image/png) and call the for_type method to register circle_to_png as the display function for MyCircle.


In [ ]:
%load soln/mycircle_png.py

In [ ]:
display_png(c)

PNG formatter for NumPy arrays

In this exercise, you will register a display formatter function that generates a PNG representation of a 2d NumPy array. Here is the function that uses the Python Imaging Library (PIL) to generate the raw PNG data:


In [ ]:
from PIL import Image
from io import BytesIO
import numpy as np

def ndarray_to_png(x):
    if len(x.shape) != 2: return
    x = np.asarray(Image.fromarray(x).resize((500, 500)))
    x = (x - x.min()) / (x.max() - x.min())
    img = Image.fromarray((x*256).astype('uint8'))
    img_buffer = BytesIO()
    img.save(img_buffer, format='png')
    return img_buffer.getvalue()

Use the for_type method of the PNG formatter to register ndarray_to_png as the display function for np.ndarray.


In [ ]:
%load soln/ndarray_png.py

Now create a few NumPy arrays and display them. Notice that their default representation in the Notebook is PNG rather than text.


In [ ]:
a = np.random.rand(100,100)

In [ ]:
a

You can still display the plain text representation using the display_pretty function.


In [ ]:
from IPython.display import display_pretty

In [ ]:
display_pretty(a)

In [ ]:
b = np.linspace(0,100.0, 100**2).reshape((100,100))

In [ ]:
b